package com.mars.base.common.logger.aspect;

import java.lang.reflect.Method;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.dandelion.commons.SystemHelper;
import com.dandelion.commons.annotation.SystemLog;
import com.dandelion.commons.constants.BaseConst;
import com.dandelion.commons.utils.StringUtils;
import com.dandelion.manager.system.domain.SysLog;
import com.dandelion.manager.system.service.SysLogService;

@Aspect
@Component
@SuppressWarnings("rawtypes")
public class SystemLogAspectHelper {

	private static final Logger logger = LogManager.getLogger(SystemLogAspectHelper.class);
	
	@Autowired
	private SysLogService service ;
	
	/**
	 * Controller层 切入点
	 */
	@Pointcut("@annotation(com.dandelion.commons.annotation.SystemLog)")
	public void controllerAspect() {
	}

	/**
	 * 前置通知 用于拦截Controller层记录用户的操作
	 * 
	 * @param point
	 * @throws Throwable 
	 */
	@Around("controllerAspect()")
	public Object doController(ProceedingJoinPoint point) throws Throwable {
		
		Object result = null;
		Long start = 0L;
		Long end = 0L;
		Long time = 0L;
		
		start = System.currentTimeMillis();
		result = point.proceed();	//执行方法所消耗的时间
		end = System.currentTimeMillis();
		time = end - start;
		
		if(SystemHelper.getCurrentUser() != null) {
			
			Object[] args = point.getArgs();
			MethodSignature signature = (MethodSignature) point.getSignature();
			String longMethod = point.getTarget().getClass().getName() + "." + point.getSignature().getName() + "()";
			SystemLog ann = (SystemLog) signature.getMethod().getAnnotation(SystemLog.class);
			String module = ann.module();
			String method = ann.method();
			String description = ann.description();
			
			try {
				SysLog sysLog = SpringContextHolder.getBean(SysLog.class) ;
				sysLog.setLogType(BaseConst.LOG_TYPE_OPERATE);
				sysLog.setUsername(SystemHelper.getCurrentUsername());
				sysLog.setTruename(SystemHelper.getCurrentTruename());
				sysLog.setActionTime(time.toString());
				sysLog.setIp(SystemHelper.getCurrentUserIp());
				sysLog.setModule(module);
				sysLog.setMethod(method);
				sysLog.setShortMethod(point.getSignature().toShortString());
				sysLog.setLongMethod(longMethod);
				sysLog.setParams(JSON.toJSONString(args));
				sysLog.setDescription(StringUtils.isNotBlank(description)?description:"");
				this.service.add(sysLog);
				
				logger.info("操作记录：[用户：{}——IP：{}——模块：{}——方法：{}——描述：{}——参数：{}]", SystemHelper.getCurrentUsername(), SystemHelper.getCurrentUserIp(), module, method, description, longMethod, description, args);
			} catch (Exception e) {
				//记录本地异常日志
				logger.error("异常信息:{}", e);    
			} 
		} else {
			logger.info("用户未登录，主要测试，不作记录！");
		}
		return result ;
	}

	/**
	 * 操作异常记录
	 * 
	 * @param point
	 * @param e
	 */
	@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint point, Throwable e) {
        
        //获取请求IP  
        String ip = SystemHelper.getCurrentUserIp();    
		
        Object[] args = point.getArgs();
        MethodSignature signature = (MethodSignature) point.getSignature();
        String longMethod = point.getTarget().getClass().getName() + "." + point.getSignature().getName() + "()";
        SystemLog ann = (SystemLog) signature.getMethod().getAnnotation(SystemLog.class);
        String module = ann.module();
        String method = ann.method();
		String description = ann.description() ;
		
 		//获取用户请求方法的参数并序列化为JSON格式字符串    
        String params = JSON.toJSONString(args);     
 		
		try {
			/* ==========数据库日志=========*/    
            SysLog sysLog = SpringContextHolder.getBean(SysLog.class) ;
	 		sysLog.setLogType(BaseConst.LOG_TYPE_EXCEPTION);
	 		sysLog.setUsername(SystemHelper.getCurrentUsername());
	 		sysLog.setTruename(SystemHelper.getCurrentTruename());
	 		sysLog.setIp(ip);
	 		sysLog.setModule(module);
	 		sysLog.setMethod(method);
	 		sysLog.setShortMethod(point.getSignature().toShortString());
	 		sysLog.setLongMethod(longMethod);
	 		sysLog.setParams(params);
	 		sysLog.setDescription(StringUtils.isNotBlank(description)?description:"<font color=\"red\">执行失败</font>");
	 		sysLog.setExceptionCode(e.getClass().getName());
	 		sysLog.setExceptionDetail(e.getMessage());
	 		this.service.add(sysLog);
			
		} catch (Exception ex) {
			//记录本地异常日志    
            logger.error("异常信息:{}", ex.getMessage());    
		}
		logger.error("====================================通知异常开始====================================");
		logger.error("请求用户名:{}", SystemHelper.getCurrentTruename()); 
		logger.error("请求用户IP:{}", ip); 
		logger.error("请求方法:{}", longMethod); 
		logger.error("请求参数:{}", params); 
		logger.error("异常代码:{}", e.getClass().getName()); 
		logger.error("异常信息:{}", e); 
		logger.error("====================================通知异常结束====================================\r\n");
	}
	
	

	/**
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 * @param joinPoint 切点
	 * @return 方法描述
	 * @throws Exception
	 */
	public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
		String targetName = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		Object[] arguments = joinPoint.getArgs();
		Class targetClass = Class.forName(targetName);
		Method[] methods = targetClass.getMethods();
		String description = "";
		for (Method method : methods) {
			if (method.getName().equals(methodName)) {
				Class[] clazzs = method.getParameterTypes();
				if (clazzs.length == arguments.length) {
					description = method.getAnnotation(SystemLog.class).description();
					break;
				}
			}
		}
		return description;
	}

}
